"""
存储桶管理服务
"""
import uuid
from slugify import slugify

from axiom_boot.di import service, autowired
from axiom_boot.database import BaseService, transactional
from axiom_boot.core.exceptions import BusinessException
from axiom_boot.filesystem import FileSystemService
from axiom_boot.logging.setup import get_logger

from src.storage.models.sys_file_bucket import SysFileBucket
from src.storage.mapper.sys_file_bucket_mapper import SysFileBucketMapper
from src.storage.mapper.sys_file_storage_mapper import SysFileStorageMapper
from src.storage.models.api_models import BucketCreateDTO
from src.storage.service.storage_service import StorageService

logger = get_logger(__name__)


@service()
class StorageBucketService(BaseService[SysFileBucket, SysFileBucketMapper]):
    """
    封装存储桶的业务逻辑。
    确保数据库记录与物理存储（本地文件夹或S3桶）同步。
    """
    fs_service: FileSystemService = autowired()
    storage_service: StorageService = autowired()
    sys_file_storage_mapper: SysFileStorageMapper = autowired()

    def __init__(self, mapper: SysFileBucketMapper = autowired()):
        super().__init__(mapper)

    @transactional
    async def create_bucket(self, dto: BucketCreateDTO) -> SysFileBucket:
        """
        创建新的存储桶。
        1. 在数据库中创建元数据记录。
        2. 在底层文件系统中创建物理存储（文件夹或S3桶）。
        """
        # 如果指定了桶名，使用指定的；否则自动生成
        if dto.bucket_name:
            bucket_name = dto.bucket_name
            # 检查指定的桶名是否已存在
            existing = await self.find_one_by_filters(bucket_name=bucket_name)
            if existing:
                raise BusinessException(f"存储桶名 '{bucket_name}' 已存在")
        else:
            # 自动生成桶名
            base_slug = slugify(dto.display_name) or "bucket"
            unique_suffix = str(uuid.uuid4())[:8]
            bucket_name = f"{base_slug}-{unique_suffix}"

            # 确保生成的名称在数据库中唯一
            existing = await self.find_one_by_filters(bucket_name=bucket_name)
            while existing:
                unique_suffix = str(uuid.uuid4())[:8]
                bucket_name = f"{base_slug}-{unique_suffix}"
                existing = await self.find_one_by_filters(bucket_name=bucket_name)

        new_bucket = SysFileBucket(
            bucket_name=bucket_name,
            display_name=dto.display_name,
            description=dto.description,
        )
        
        # 先保存数据库记录
        await self.save(new_bucket)
        
        try:
            # 再创建物理存储
            logger.info(f"正在创建物理存储桶: '{bucket_name}'...")
            await self.fs_service.create_bucket(bucket_name=new_bucket.bucket_name)
            logger.info(f"物理存储桶 '{bucket_name}' 创建成功。")
        except Exception as e:
            # 如果物理创建失败，则事务应回滚，数据库记录不应被提交。
            logger.error(f"物理存储桶创建失败，将回滚数据库操作: {e}", exc_info=True)
            raise BusinessException(f"创建物理存储桶失败: {e}")

        return new_bucket

    @transactional
    async def delete_bucket(self, bucket_id: int):
        """
        物理删除存储桶 (谨慎使用)。
        1. 检查桶是否为空。
        2. 删除物理存储。
        3. 删除数据库记录。
        """
        bucket = await self.find_by_pk_or_fail(bucket_id)

        is_empty = await self.storage_service.is_bucket_empty(bucket.bucket_name)
        if not is_empty:
            raise BusinessException("不能删除非空存储桶，请先清空里面的所有文件和文件夹。")

        try:
            logger.info(f"正在删除物理存储桶: '{bucket.bucket_name}'...")
            await self.fs_service.delete_bucket(bucket_name=bucket.bucket_name)
            logger.info(f"物理存储桶 '{bucket.bucket_name}' 删除成功。")
        except Exception as e:
            logger.error(f"物理存储桶删除失败，但将继续删除数据库记录: {e}", exc_info=True)

        await self.delete_by_pk(bucket_id, hard_delete=True)

    @transactional
    async def logical_delete_bucket(self, bucket_id: int):
        """
        逻辑删除存储桶及其下的所有文件记录。
        """
        # 1. 查找此桶
        bucket = await self.find_by_pk_or_fail(bucket_id)
        
        # 2. 查找此桶下的所有文件
        files_to_delete = await self.sys_file_storage_mapper.find_by_filters(bucket=bucket.bucket_name)
        if files_to_delete:
            # 3. 批量逻辑删除文件记录
            file_ids = [f.id for f in files_to_delete]
            await self.sys_file_storage_mapper.soft_delete_by_pks(file_ids)
        
        # 4. 逻辑删除存储桶本身
        await self.delete_by_pk(bucket_id)
